//+---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation, 2008
//
// File: DataPointsEventLogger.cs
//
// Contents: Event Logger singleton for Data Points Logger
//
// Created by: Andrew Lin (yunlin@microsoft.com) July 2nd, 2008
//
//----------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Threading;

namespace Microsoft.Reputation.Services
{
    public static class DataPointsEventLogger
    {
        private const int ProcessQueueGetFileInfoEventId = 0;
        private const int PerformanceCountersInitializationEventId = 1;
        private const int ProcessQueueStreamWriteEventId = 2;
        private const int ProcessQueueStreamFlushEventId = 3;
        private const int ProcessQueueCreateNewFileEventId = 4;
        private const int ProcessQueueGetNewFileEventId = 5;
        private const int ProcessFailedQueueMoveFileEventId = 6;
        private const int ProcessFailedQueueMoveFileMaxEventId = 7;
        private const int GetNewLogFileMoveEventId = 8;
        private const int GetNewLogFileMoveToFailPathEventId = 9;
        private const int GetNewLogFileDelTempEventId = 10;

        private const int EventSucceedState = 1;
        private const int EventFailureState = 0;

        private static int s_processQueueGetFileInfoState = EventSucceedState;
        private static int s_processQueueStreamWriteState = EventSucceedState;
        private static int s_processQueueStreamFlushState = EventSucceedState;
        private static int s_processQueueCreateNewFileState = EventSucceedState;
        private static int s_processQueueGetNewFileState = EventSucceedState;
        private static int s_processFailedQueueMoveFileState = EventSucceedState;
        private static int s_processFailedQueueMoveFileMaxState = EventSucceedState;
        private static int s_getNewLogFileMoveState = EventSucceedState;
        private static int s_getNewLogFileMoveToFailPathState = EventSucceedState;
        private static int s_getNewLogFileDelTempState = EventSucceedState;

        private static EventLog s_eventLog;
        private static int s_eventIdBase = 221;
        private static int s_antiEventIdBase = 321;
        private static bool s_eventLoggerActive;
        private static bool s_eventLoggerThrottleDisabled = false;

        /// <summary>
        /// Set only Accessor for the starting Event ID from the calling application
        /// </summary>
        public static int EventIdBase
        {
            set
            {
                s_eventIdBase = value;
            }
        }

        /// <summary>
        /// Set only Accessor for the starting Anti Event ID from the calling application
        /// </summary>
        public static int AntiEventIdBase
        {
            set
            {
                s_antiEventIdBase = value;
            }
        }

        /// <summary>
        /// Set only Accessor for the Event Log from the calling application
        /// </summary>
        public static EventLog EventLog
        {
            get
            {
                return s_eventLog;
            }
            set
            {
                s_eventLog = value;
            }
        }

        /// <summary>
        /// Set only Accessor for enable Event Logger from the calling application
        /// </summary>
        public static bool EventLoggerActive
        {
            set
            {
                s_eventLoggerActive = value;
            }
        }

        /// <summary>
        /// Set only Accessor for enable Event Logger from the calling application
        /// </summary>
        public static bool EventLoggerThrottleDisabled
        {
            set
            {
                s_eventLoggerThrottleDisabled = value;
            }
        }

        public static void LogProcessQueueGetFileInfoSuccess()
        {
            LogSuccessEvent(
                ref s_processQueueGetFileInfoState,
                s_antiEventIdBase + ProcessQueueGetFileInfoEventId);
        }

        public static void LogProcessQueueGetFileInfoFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_processQueueGetFileInfoState,
                s_eventIdBase + ProcessQueueGetFileInfoEventId,
                errorMsg);
        }

        public static void LogProcessQueueStreamWriteSuccess()
        {
            LogSuccessEvent(
                ref s_processQueueStreamWriteState,
                s_antiEventIdBase + ProcessQueueStreamWriteEventId);
        }

        public static void LogProcessQueueStreamWriteFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_processQueueStreamWriteState,
                s_eventIdBase + ProcessQueueStreamWriteEventId,
                errorMsg);
        }

        public static void LogProcessQueueStreamFlushSuccess()
        {
            LogSuccessEvent(
                ref s_processQueueStreamFlushState,
                s_antiEventIdBase + ProcessQueueStreamFlushEventId);
        }

        public static void LogProcessQueueStreamFlushFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_processQueueStreamFlushState,
                s_eventIdBase + ProcessQueueStreamFlushEventId,
                errorMsg);
        }

        public static void LogProcessQueueCreateNewFileSuccess()
        {
            LogSuccessEvent(
                ref s_processQueueCreateNewFileState,
                s_antiEventIdBase + ProcessQueueCreateNewFileEventId);
        }

        public static void LogProcessQueueCreateNewFileFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_processQueueCreateNewFileState,
                s_eventIdBase + ProcessQueueCreateNewFileEventId,
                errorMsg);
        }

        public static void LogProcessQueueGetNewFileSuccess()
        {
            LogSuccessEvent(
                ref s_processQueueGetNewFileState,
                s_antiEventIdBase + ProcessQueueGetNewFileEventId);
        }

        public static void LogProcessQueueGetNewFileFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_processQueueGetNewFileState,
                s_eventIdBase + ProcessQueueGetNewFileEventId,
                errorMsg);
        }

        public static void LogProcessFailedQueueMoveFileSuccess()
        {
            LogSuccessEvent(
                ref s_processFailedQueueMoveFileState,
                s_antiEventIdBase + ProcessFailedQueueMoveFileEventId);
        }

        public static void LogProcessFailedQueueMoveFileFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_processFailedQueueMoveFileState,
                s_eventIdBase + ProcessFailedQueueMoveFileEventId,
                errorMsg);
        }

        public static void LogProcessFailedQueueMoveFileMaxSuccess()
        {
            LogSuccessEvent(
                ref s_processFailedQueueMoveFileMaxState,
                s_antiEventIdBase + ProcessFailedQueueMoveFileMaxEventId);
        }

        public static void LogProcessFailedQueueMoveFileMaxFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_processFailedQueueMoveFileMaxState,
                s_eventIdBase + ProcessFailedQueueMoveFileMaxEventId,
                errorMsg);
        }

        public static void LogGetNewLogFileMoveSuccess()
        {
            LogSuccessEvent(
                ref s_getNewLogFileMoveState,
                s_antiEventIdBase + GetNewLogFileMoveEventId);
        }

        public static void LogGetNewLogFileMoveFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_getNewLogFileMoveState,
                s_eventIdBase + GetNewLogFileMoveEventId,
                errorMsg);
        }

        public static void LogGetNewLogFileMoveToFailPathSuccess()
        {
            LogSuccessEvent(
                ref s_getNewLogFileMoveToFailPathState,
                s_antiEventIdBase + GetNewLogFileMoveToFailPathEventId);
        }

        public static void LogGetNewLogFileMoveToFailPathFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_getNewLogFileMoveToFailPathState,
                s_eventIdBase + GetNewLogFileMoveToFailPathEventId,
                errorMsg);
        }

        public static void LogGetNewLogFileDelTempSuccess()
        {
            LogSuccessEvent(
                ref s_getNewLogFileDelTempState,
                s_antiEventIdBase + GetNewLogFileDelTempEventId);
        }

        public static void LogGetNewLogFileDelTempFailure(string errorMsg)
        {
            LogFailureEvent(
                ref s_getNewLogFileDelTempState,
                s_eventIdBase + GetNewLogFileDelTempEventId,
                errorMsg);
        }

        public static void LogPerformanceCountersInitializationSuccess()
        {
            CommonEventLogger.LogServiceEvent("DataPointsLogger performance counters initialized",
                s_antiEventIdBase + PerformanceCountersInitializationEventId);
        }

        public static void LogPerformanceCountersInitializationFailure(string errorMsg)
        {
            CommonEventLogger.LogServiceEvent(
                String.Format("DataPointsLogger performance counters failed to initialize Error:{0}", errorMsg),
                s_eventIdBase + PerformanceCountersInitializationEventId, EventLogEntryType.Error);
        }

        private static void LogSuccessEvent(
            ref int eventState,
            int eventId)
        {
            try
            {
                //
                // Log the first success after the serial of failures, if throttling is turned on.
                //
                if (!s_eventLoggerThrottleDisabled &&
                    Interlocked.CompareExchange(
                        ref eventState,
                        EventSucceedState,
                        EventFailureState) == EventFailureState)
                {
                    if (s_eventLoggerActive)
                    {
                        lock (s_eventLog)
                        {
                            //
                            // Write the success message to event log.
                            //
                            s_eventLog.WriteEntry(
                                "The failure associated with the previous Error " + eventId + " has been resolved, and the operation succeeded.",
                                EventLogEntryType.Information,
                                eventId);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                TraceUtility.TraceCatchException(DiagnosticTracing.Source, ex);
                s_eventLoggerActive = false;
            }
        }

        private static void LogFailureEvent(
            ref int eventState,
            int eventId,            
            string errorMsg)
        {
            try
            {
                //
                // Only log the first success after the serial of failures, if throttling is turned on.
                //
                if (s_eventLoggerThrottleDisabled ||
                    Interlocked.CompareExchange(
                        ref eventState,
                        EventFailureState,
                        EventSucceedState) == EventSucceedState)
                {
                    if (string.IsNullOrEmpty(errorMsg))
                    {
                        TraceUtility.TraceAssert(DiagnosticTracing.Source, false, "Error message for storage event log is null or empty.");
                        return;
                    }

                    if (s_eventLoggerActive)
                    {
                        lock (s_eventLog)
                        {
                            //
                            // Write the error message to event log.
                            //
                            s_eventLog.WriteEntry(
                                errorMsg, 
                                EventLogEntryType.Error,
                                eventId);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                TraceUtility.TraceCatchException(DiagnosticTracing.Source, ex);
                s_eventLoggerActive = false;
            }
        }
    }
}
